//题目:
// 给你一个整数数组 coins 表示不同面额的硬币，另给一个整数 amount 表示总金额。
// 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额，返回 0 。
// *假设每一种面额的硬币有无限个。 
// 题目数据保证结果符合 32 位带符号整数。
#include<iostream>
#include<limits.h>
#include<vector>

using namespace std;
//代码
class Solution 
{
public:
    int change(int amount, vector<int>& coins) 
    {
        // int n=coins.size();
        // //1.创建dp表————dp[i][j]表示：选到第i个元素、总金额为j时，最大组合数
        // vector<vector<long long>> dp(n+1,vector<long long>(amount+1));
        // //2.初始化
        // dp[0][0]=1;
        // //3.填表————动态转移方程：dp[i][j]+=dp[i-1][j]+dp[i-1][j-k*coins[i]]
        // for(int i=1;i<=n;i++)
        // {
        //     for(int j=0;j<=amount;j++)
        //     {
        //         //暴力遍历
        //         // for(int k=0;k*coins[i-1]<=j;k++)
        //         //     dp[i][j]+=(dp[i-1][j-k*coins[i-1]])%INT_MAX;

        //         //数学优化
        //         dp[i][j]=dp[i-1][j]%INT_MAX;
        //         if(j-coins[i-1]>=0)
        //             dp[i][j]+=dp[i][j-coins[i-1]]%INT_MAX;
        //     }
        // }
        // //4.确定返回值
        // return dp[n][amount];

        //空间优化
        int n=coins.size();
        //1.创建dp表————dp[i][j]表示：选到第i个元素、总金额为j时，最大组合数
        vector<long long> dp(amount+1);
        //2.初始化
        dp[0]=1;
        //3.填表————动态转移方程：dp[i][j]+=dp[i-1][j]+dp[i-1][j-k*coins[i]]
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=amount;j++)
            {
                //暴力遍历
                // for(int k=0;k*coins[i-1]<=j;k++)
                //     dp[i][j]+=(dp[i-1][j-k*coins[i-1]])%INT_MAX;

                //数学优化
                if(j-coins[i-1]>=0)
                    dp[j]+=dp[j-coins[i-1]]%INT_MAX;
            }
        }
        //4.确定返回值
        return dp[amount];
    }
};